using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Utils;
using Me.Prettyprint.Hector.Api.Ddl;

namespace Me.Prettyprint.Cassandra.Serializers
{
    /// <summary>
    /// Base class for serializers. Cassandra stores all data as bytes. The client
    /// uses type specific serializers to convert from the object to bytes. Subclasses
    /// need to implement to/from bytes method.
    /// 
    /// Note that .Net uses different byte order than Java. This means it maybe necessary
    /// to convert to/from big/little endian. It is up to the developer to decide the
    /// best place for the logic. In the case of classes like BigDecimal, the conversion
    /// is done in BigDecimal, not in the serializer.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class AbstractSerializer<T> : Me.Prettyprint.Hector.Api.Serializer<T>
    {
        public virtual ComparatorType GetComparatorType()
        {
            return ComparatorType.BYTESTYPE;
        }
        public abstract byte[] ToBytes(T obj);
        public abstract ByteBuffer ToByteBuffer(T obj);
        public abstract T FromBytes(byte[] bytes);
        public abstract T FromByteBuffer(ByteBuffer buff);
        public Dictionary<byte[], V> ToBytesDictionary<V>(Dictionary<T, V> dictionary)
        {
            Dictionary<byte[], V> bytesMap = new Dictionary<byte[], V>();
            foreach (T entry in dictionary.Keys)
            {
                V val = dictionary[entry];
                bytesMap[ToBytes(entry)] = val;
            }
            return bytesMap;
        }
        public Dictionary<T, V> FromBytesDictionary<V>(Dictionary<byte[], V> dictionary)
        {
            Dictionary<T, V> objMap = new Dictionary<T, V>();
            foreach (byte[] entry in dictionary.Keys)
            {
                objMap[FromBytes(entry)] = dictionary[entry];
            }
            return objMap;
        }
        public virtual List<byte[]> ToBytesList(List<T> list)
        {
            List<byte[]> bytesList = new List<byte[]>(list.Count);
            foreach (T s in list)
            {
                bytesList.Add(ToBytes(s));
            }
            return bytesList;
        }
        public virtual List<T> FromBytesList(List<byte[]> list)
        {
            List<T> objList = new List<T>(list.Count);
            foreach (byte[] s in list)
            {
                objList.Add(FromBytes(s));
            }
            return objList;
        }
        virtual public ComparatorType ComparatorType
        {
            get
            {
                return ComparatorType.BYTESTYPE;
            }
        }
        public int ComputeInitialHashSize(int initialSize)
        {
            return ((int)(initialSize / 0.75)) + 1;
        }
        public byte[] ConvertToBigEndianBytes(byte[] bytes)
        {
            byte[] clone = (byte[])bytes.Clone();
            if (System.BitConverter.IsLittleEndian)
            {
                Array.Reverse(clone);
                return clone;
            }
            return bytes;
        }
        public byte[] ConvertFromBigEndianBytes(byte[] bytes)
        {
            byte[] clone = (byte[])bytes.Clone();
            if (System.BitConverter.IsLittleEndian)
            {
                Array.Reverse(clone);
                return clone;
            }
            return bytes;
        }
        protected static void ReverseLowFieldTimestamp(byte[] guid)
        {
            Array.Reverse(guid, 0, 4);
        }
        protected static void ReverseMiddleFieldTimestamp(byte[] guid)
        {
            Array.Reverse(guid, 4, 2);
        }
        protected static void ReverseHighFieldTimestamp(byte[] guid)
        {
            Array.Reverse(guid, 6, 2);
        }
    }
}